using System;
using System.Collections.Generic;
using System.Text;
using Tiago.Data;
using Nihonaid.classes.scheduler;
using System.Windows.Forms;
using System.Collections;

namespace Nihonaid.classes
{
    partial class LearningQueue
    {
        /// <summary>
        /// The knowledge database interface
        /// </summary>
        private DBWrapper db = new DBWrapper(Application.StartupPath + "\\data\\learning_db.mdb", "Admin", "");

        /// <summary>
        /// A priority queue with the unlearned items
        /// </summary>
        public List<LearningItem> learning_queue;

        /// <summary>
        /// A priority queue with the items that were already learnt but require repetition
        /// </summary>
        public List<LearningItem> review_queue;

        /// <summary>
        /// The review scheduler
        /// </summary>
        public IScheduler scheduler;

        /// <summary>
        /// Indicates the number of sequential correct answers necessary to consider the item learned
        /// </summary>
        private const int streak_necessary_learn = 3;

        /// <summary>
        /// Indicates if the last fetched item (from a queue) was a review item or an unlearned item
        /// </summary>
        private bool last_fetched_review;

        /// <summary>
        /// The queue's constructor
        /// </summary>
        public LearningQueue()
        {
            this.scheduler = new PimsleurScheduler();
            this.learning_queue = new List<LearningItem>();
            this.review_queue = new List<LearningItem>();
            InitializeQueues();
        }

        /// <summary>
        /// Fills the learning queue with the reviewable learning items
        /// </summary>
        private void InitializeQueues()
        {
            this.review_queue.Clear();
            this.learning_queue.Clear();

            // Retrieves every item scheduled for a time before now
            DBWrapper.Results results = db.Select("*", "LearningItems", "", "id");

            // Insert every item into the appropriate queue
            for (int x = 0; x < results.getNumberRows(); x++)
            {
                LearningItem item = new LearningItem();
                item.ID = int.Parse(results.Get("id", x));
                item.Question = results.Get("question", x);
                item.Answer = results.Get("answer", x);
                item.CorrectAnswers = int.Parse(results.Get("correct_answers", x));
                item.WrongAnswers = int.Parse(results.Get("wrong_answers", x));
                item.CorrectStreak = int.Parse(results.Get("correct_streak", x));
                item.CategoryID = (LearningItem.QuestionType)int.Parse(results.Get("id_category", x));
                item.Mnemonic = results.Get("mnemonic", x);
                item.LastRepetitionDate = DateTime.Parse(results.Get("last_repetition_date", x));
                item.NextRepetitionDate = DateTime.Parse(results.Get("next_repetition_date", x));
                item.CategoryName = this.db.Select("category_name", "LearningItemCategories", "LearningItemCategories.id = " + (int)item.CategoryID).Get("category_name", 0);
                item.Order = int.Parse(results.Get("order", x));

                // If the item was already answered once then insert it into the review queue
                if (item.CorrectAnswers > 0)
                    this.review_queue.Add(item);
                else // otherwise insert it in the learning queue
                    this.learning_queue.Add(item);
            }

            this.learning_queue.Sort();
            this.review_queue.Sort();
        }

        /// <summary>
        /// Returns the number of items in the learning queue
        /// </summary>
        /// <returns>Number of items in the learning queue</returns>
        public int GetLearningItemsLeft()
        {
            return this.learning_queue.Count;
        }

        /// <summary>
        /// Returns the number of items in the review queue
        /// </summary>
        /// <returns>Number of items in the review queue</returns>
        public int GetReviewItemsLeft()
        {
            int count = 0;
            for (int x = 0; x < this.review_queue.Count; x++)
                if (((LearningItem)this.review_queue[x]).NextRepetitionDate <= DateTime.Now)
                    count++;
            return count;
        }

        /// <summary>
        /// Returns the number of learned hiragana
        /// </summary>
        /// <param name="type">The type of learning item to count</param>
        /// <returns>Number of learned items of the given type</returns>
        public int CountLearningItemLearned(LearningItem.QuestionType type)
        {
            string where = "correct_streak >= " + streak_necessary_learn + " AND id_category = " + (int)type;
            DBWrapper.Results results_known = db.Select("id", "LearningItems", where);
            int known = results_known.getNumberRows();
            return known;
        }

        /// <summary>
        /// Returns the number of hiragana in the database
        /// </summary>
        /// <param name="type">The type of learning item to count</param>
        /// <returns>Number of items of the given type</returns>
        public int CountLearningItemTotal(LearningItem.QuestionType type)
        {
            string where = "id_category = " + (int)type;
            DBWrapper.Results results = db.Select("id", "LearningItems", where);
            int total = results.getNumberRows();
            return total;
        }

        /// <summary>
        /// Updates the learning item in the database
        /// </summary>
        /// <param name="current_item">The item object to be updated in the database</param>
        private void UpdateLearningItemDatabase(LearningItem current_item)
        {
            string table = "LearningItems";
            string update = "";
            update += "correct_answers = " + current_item.CorrectAnswers;
            update += ",wrong_answers = " + current_item.WrongAnswers;
            update += ",correct_streak = " + current_item.CorrectStreak;
            update += ",next_repetition_date = '" + current_item.NextRepetitionDate + "'";
            update += ",last_repetition_date = '" + current_item.LastRepetitionDate + "'";
            //update += ",mnemonic = '" + current_item.Mnemonic + "'";
            string where = "id = " + current_item.ID;
            this.db.Update(table, update, where);
        }
    }
}